#define _CRT_SECURE_NO_WARNINGS
#include "timestamp.h"

#include <sstream>
#include <iomanip>
#include <chrono>

#ifdef WIN32
#define THREAD_LOCAL __declspec(thread)
#else
#define THREAD_LOCAL  __thread
#endif // DEBUG

namespace { 
    THREAD_LOCAL  int64_t  local_last_second;
    THREAD_LOCAL  char local_last_formate_time[32];
}

namespace easyasio {
namespace base {

Timestamp::Timestamp(int64_t microseconds)
    : microSecondsSinceEpoch_(microseconds)
{
}

std::string Timestamp::toString() const
{
    char buf[32] = { 0 };
    int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond;
    int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond;
#if WIN32
    sprintf_s(buf, "%d.%06d", seconds, microseconds);
#else
    snprintf(buf, sizeof buf, "%d.%06d", seconds, microseconds);
#endif
    return buf;
}

std::string Timestamp::toFormattedStringCorrectToSecs() const
{
    std::time_t seconds = static_cast<std::time_t>(microSecondsSinceEpoch_ / kMicroSecondsPerSecond);

    if (seconds != local_last_second)
    {
        local_last_second = seconds;
        struct std::tm timval = {0};
#if WIN32
        localtime_s(&timval, &seconds);
        sprintf_s(local_last_formate_time, "%4d%02d%02d-%02d%02d%02d", timval.tm_year + 1900, 
            timval.tm_mon + 1, timval.tm_mday, timval.tm_hour, timval.tm_min, timval.tm_sec);
#else
        localtime_r(&seconds, &timval);
        snprintf(local_last_formate_time, sizeof local_last_formate_time, "%4d%02d%02d-%02d%02d%02d", timval.tm_year + 1900, 
            timval.tm_mon + 1, timval.tm_mday, timval.tm_hour, timval.tm_min, timval.tm_sec);
#endif

    }
    
    return local_last_formate_time;
}

std::string Timestamp::toFormattedStringCorrectToMicrosecs() const
{   
    std::time_t seconds = static_cast<std::time_t>(microSecondsSinceEpoch_ / kMicroSecondsPerSecond);
    int microseconds = static_cast<int>(microSecondsSinceEpoch_ % kMicroSecondsPerSecond);

    if (seconds != local_last_second)
    {
        local_last_second = seconds;
        struct std::tm timval = {0};
#if WIN32
        localtime_s(&timval, &seconds);
        sprintf_s(local_last_formate_time, "%4d%02d%02d %02d:%02d:%02d.%06d", timval.tm_year + 1900, 
            timval.tm_mon + 1, timval.tm_mday, timval.tm_hour, timval.tm_min, timval.tm_sec, microseconds);
#else
        localtime_r(&seconds, &timval);
        snprintf(local_last_formate_time, sizeof local_last_formate_time, "%4d%02d%02d %02d:%02d:%02d.%06d", timval.tm_year + 1900, 
            timval.tm_mon + 1, timval.tm_mday, timval.tm_hour, timval.tm_min, timval.tm_sec, microseconds);
#endif
    }
    
    return local_last_formate_time;
}

Timestamp Timestamp::now()
{
    std::chrono::microseconds end = 
        std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now().time_since_epoch());
    return Timestamp(end.count());
}

Timestamp Timestamp::invalid()
{
    return Timestamp();
}

} 
}
